//! \file Neuron.h
//! \brief Defines the <code>fullsail_ai::Neuron</code> class.
//! \author Cromwell D. Enage
#ifndef _FULLSAIL_AI_NEURON_H_
#define _FULLSAIL_AI_NEURON_H_

#include <vector>

namespace fullsail_ai {

	//! \brief Logical representation of a neuron.
	//!
	//! This class is responsible for handling low-level operations on a neuron's weights and bias.
	//!
	//! \note
	//!   - The arguments and the weights are kept in separate containers.
	//!   - The bias is kept separate from the rest of the weights.
	//!   - User code must maintain its container of inputs.
	//!   - The activation value is computed by a member function rather than stored as a member
	//!     variable.
	//!   - User code must store the associated error in a container outside this class.
	class Neuron
	{
		std::vector<double> weights;
		double              bias;

	public:
		//! \brief Returns the current values of this neuron's weights.
		//!
		//! \return  The neuron's weights.
		inline std::vector<double> const& getWeights() const
		{
			return weights;
		}

		//! \brief Returns the current value of this neuron's bias.
		//!
		//! \return  The neuron's bias.
		inline double getBias() const
		{
			return bias;
		}

		//! \brief Initializes the weights and bias of this neuron.
		//!
		//! If \a numberGenerator generates random numbers, then the weights and bias will also be
		//! random.
		//!
		//! \param   argumentCount    the number of elements in each \a arguments container that
		//!                           will be passed in as an argument to subsequent
		//!                           <code>computeActivationValue()</code> calls.
		//! \param   numberGenerator  a zero-argument function that returns a different integer
		//!                           on each invocation.
		//!
		//! \pre
		//!   - <code>0 \<</code> \a argumentCount
		//!   - The range of \a numberGenerator is <code>[0, RAND_MAX]</code>.
		//! \post
		//!   - The range of each element in <code>getWeights()</code> is <code>[-0.5, 0.5]</code>.
		//!   - The range of <code>getBias()</code> is <code>[-0.5, 0.5]</code>.
		//!   - There are as many weights as there will be elements in the aforementioned
		//!     \a arguments container.
		void initialize(std::size_t argumentCount, int (*numberGenerator)());

		//! \brief Computes the neuron's activation value.
		//!
		//! \param   arguments          the container of arguments that this neuron will evaluate.
		//! \return  the output of this neuron.
		//!
		//! \pre
		//!   - There are as many elements in the \a arguments container as there are weights.
		double computeActivationValue(std::vector<double> const& arguments) const;

		//! \brief Adjusts the weights and bias of this neuron.
		//!
		//! \param   arguments       the container of arguments that were used to calculate the
		//!                          neuron's actual value.
		//! \param   valueError      the error in this neuron's output.
		//! \param   learningFactor  the rate at which the overall network makes progress in
		//!                          learning.
		//!
		//! \pre
		//!   - There are as many elements in the \a arguments container as there are weights.
		//!   - <code>0 \<</code> \a learningFactor
		void adjust(std::vector<double> const& arguments, double valueError,
		            double learningFactor);
	};
}  // namespace fullsail_ai

#endif  // _FULLSAIL_AI_NEURON_H_

